import json
import tkinter as tk
from tkinter import messagebox


# 1. Define core classes
class Student:
    def __init__(self, username, fullName, age, school, interests, relations, followed_courses):
        self.username = username
        self.fullName = fullName
        self.age = age
        self.school = school
        self.interests = interests
        self.relations = relations
        # Courses the student is following
        self.followed_courses = followed_courses
        # IDs of completed courses
        self.completed_course_ids = []
        # Grades for each course (course ID: grade)
        self.course_grades = {}

class Course:
    def __init__(self, course_id, title, department, credits, professor, schedule, description, prerequisites):
        self.course_id = course_id
        self.title = title
        self.department = department
        self.credits = credits
        self.professor = professor
        self.schedule = schedule
        # Course description
        self.description = description
        # Prerequisite courses
        self.prerequisites = prerequisites

class SimpleQueue:
    def __init__(self):
        self.items = []

    def enqueue(self, item):
        self.items.append(item)

    def dequeue(self):
        return self.items.pop(0) if self.items else None

    def is_empty(self):
        return len(self.items) == 0

# 2. Load JSON files
def load_courses_from_file(file_path):
    try:
        # Open the JSON file and load the data
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)

        courses = []
        for course_data in data['courses']:
            # Extract course information from the JSON data
            course_id = course_data['courseId']
            title = course_data['title']
            department = course_data.get('department', '')
            credits = course_data.get('credits', 0)
            professor = course_data.get('professor', '')
            schedule = course_data.get('schedule', {})
            description = course_data.get('description', '')
            prerequisites = course_data.get('prerequisites', [])

            # Create a Course object and add it to the list
            courses.append(Course(course_id, title, department, credits, professor, schedule, description, prerequisites))
        return courses
    except FileNotFoundError:
        print(f"Error: The file {file_path} was not found.")
        return []
    except json.JSONDecodeError:
        print(f"Error: Failed to decode JSON from {file_path}.")
        return []

def load_students_from_file(file_path):
    try:
        # Open the JSON file and load the data
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)

        students = []
        for student_data in data['students']:
            # Extract student information from the JSON data
            username = student_data['username']
            fullName = student_data['fullName']
            age = student_data['age']
            school = student_data['school']
            interests = student_data['interests']
            relations = student_data['relations']
            followed_courses = student_data['followed_courses']

            # Create a Student object and add it to the list
            students.append(Student(username, fullName, age, school, interests, relations, followed_courses))
        return students
    except FileNotFoundError:
        print(f"Error: The file {file_path} was not found.")
        return []
    except json.JSONDecodeError:
        print(f"Error: Failed to decode JSON from {file_path}.")
        return []

def load_grades_from_file(file_path):
    try:
        # Open the JSON file and load the data
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
        return data['grades_per_course']
    except FileNotFoundError:
        print(f"Error: The file {file_path} was not found.")
        return {}
    except json.JSONDecodeError:
        print(f"Error: Failed to decode JSON from {file_path}.")
        return {}

# 3. Implement core functions
def merge_sort(students, key=None):
    if len(students) <= 1:
        return students
    mid = len(students) // 2
    left = merge_sort(students[:mid], key)
    right = merge_sort(students[mid:], key)
    return merge(left, right, key)

def merge(left, right, key):
    merged = []
    i = j = 0
    while i < len(left) and j < len(right):
        left_val = get_key_value(left[i], key)
        right_val = get_key_value(right[j], key)

        if left_val <= right_val:
            merged.append(left[i])
            i += 1
        else:
            merged.append(right[j])
            j += 1
    merged.extend(left[i:])
    merged.extend(right[j:])
    return merged

def get_key_value(student, key):
    if callable(key):
        # If the key is a function, call it with the student object
        return key(student)
    elif key == 'fullName':
        # If the key is 'fullName', return the student's full name
        return student.fullName
    elif key == 'average_score':
        # If the key is 'average_score', calculate the average score
        scores = list(student.course_grades.values())
        return sum(scores) / len(scores) if scores else 0
    else:
        # If the key is invalid, raise an error
        raise ValueError("Invalid key")

def can_enroll(student, course):
    # Check if the student has completed all prerequisite courses
    return all(prereq in student.completed_course_ids for prereq in course.prerequisites)

# 4. Initialize data
COURSE_JSON_PATH = r"C:\Users\Lenovo\Desktop\honkai-peace---project\resources\courses.json"
STUDENT_JSON_PATH = r"C:\Users\Lenovo\Desktop\honkai-peace---project\resources\students.json"
GRADES_JSON_PATH = r"C:\Users\Lenovo\Desktop\honkai-peace---project\resources\grades.json"

# Load courses from the JSON file
courses = load_courses_from_file(COURSE_JSON_PATH)
students = load_students_from_file(STUDENT_JSON_PATH)
grades = load_grades_from_file(GRADES_JSON_PATH)

# Initialize student course data
for student in students:
    for course_id, grade_list in grades.items():
        if student.username in grade_list:
            # Add the course ID to the list of completed courses
            student.completed_course_ids.append(course_id)
            # Convert grade list elements to float and calculate the average grade
            grade_list = [float(grade) for grade in grade_list[student.username]]
            student.course_grades[course_id] = sum(grade_list) / len(grade_list)

# Create a scheduling queue
scheduling_queue = SimpleQueue()
# Add a scheduling request to the queue
scheduling_queue.enqueue("Adjust the schedule of CS101")
# Add another scheduling request to the queue
scheduling_queue.enqueue("Add a laboratory for MATH101")

"""
# 5. Command-line interactive interface
def main_menu():
    while True:
        print("\n=== Honkai-Peace Course Management System ===")
        print("1. View all courses")
        print("2. Sort students by name")
        print("3. Sort students by average score")
        print("4. Check enrollment eligibility")
        print("5. Process scheduling requests")
        print("6. Sort students by course grade")
        print("7. Exit")
        choice = input("Please enter your choice: ")

        if choice == "1":
            print("\nCourse List:")
            for course in courses:
                # Format prerequisite courses as a string
                prereqs = ", ".join(course.prerequisites) if course.prerequisites else "None"
                print(f"- {course.course_id}: {course.title} (Prerequisites: {prereqs})")

        elif choice == "2":
            # Sort students by full name
            sorted_students = merge_sort(students.copy(), key='fullName')
            print("\nStudents sorted by name:")
            for s in sorted_students:
                print(f"- {s.fullName}")

        elif choice == "3":
            # Sort students by average score
            sorted_students = merge_sort(students.copy(), key='average_score')
            print("\nStudents sorted by average score:")
            for s in sorted_students:
                print(f"- {s.fullName} (Average Score: {s.course_grades})")

        elif choice == "4":
            student_username = input("Student username: ")
            course_id = input("Course ID: ")
            # Find the student by username
            student = next((s for s in students if s.username == student_username), None)
            # Find the course by course ID
            course = next((c for c in courses if c.course_id == course_id), None)
            if student and course:
                if can_enroll(student, course):
                    print(f"\n✅ {student.fullName} is eligible to enroll in {course_id}")
                else:
                    # Find missing prerequisite courses
                    missing = [p for p in course.prerequisites if p not in student.completed_course_ids]
                    print(f"\n❌ Unable to enroll: Missing prerequisite courses {', '.join(missing)}")
            else:
                print("Error: Student or course does not exist")

        elif choice == "5":
            if scheduling_queue.is_empty():
                print("\nNo pending scheduling requests")
            else:
                req = scheduling_queue.dequeue()
                print(f"\nProcessing request: {req}")
                print(f"Remaining requests: {len(scheduling_queue.items)}")

        elif choice == "6":
            course_id = input("Course ID: ")
            # Collect students enrolled in the course
            enrolled_students = [s for s in students if course_id in s.course_grades]
            if not enrolled_students:
                print("Error: No students are enrolled in this course")
                continue
            # Sort students by course grade
            sorted_students = merge_sort(enrolled_students.copy(), key=lambda s: s.course_grades[course_id])
            print(f"\nStudents sorted by {course_id} grade:")
            for s in sorted_students:
                print(f"- {s.fullName}: {s.course_grades[course_id]}")

        elif choice == "7":
            print("Exiting the system")
            break

        else:
            print("Invalid choice")
            
if __name__ == "__main__":

"""

# 5. GUI functions
def view_all_courses():
    course_list = ""
    for course in courses:
        prereqs = ", ".join(course.prerequisites) if course.prerequisites else "None"
        course_list += f"- {course.course_id}: {course.title} (Prerequisites: {prereqs})\n"
    messagebox.showinfo("Course List", course_list)


def sort_students_by_name():
    sorted_students = merge_sort(students.copy(), key='fullName')
    student_list = ""
    for s in sorted_students:
        student_list += f"- {s.fullName}\n"
    messagebox.showinfo("Students sorted by name", student_list)


def sort_students_by_average_score():
    sorted_students = merge_sort(students.copy(), key='average_score')
    student_list = ""
    for s in sorted_students:
        student_list += f"- {s.fullName} (Average Score: {s.course_grades})\n"
    messagebox.showinfo("Students sorted by average score", student_list)


def check_enrollment_eligibility():
    student_username = entry_username.get()
    course_id = entry_course_id.get()
    student = next((s for s in students if s.username == student_username), None)
    course = next((c for c in courses if c.course_id == course_id), None)
    if student and course:
        if can_enroll(student, course):
            messagebox.showinfo("Enrollment Eligibility", f"{student.fullName} is eligible to enroll in {course_id}")
        else:
            missing = [p for p in course.prerequisites if p not in student.completed_course_ids]
            messagebox.showerror("Enrollment Eligibility", f"Unable to enroll: Missing prerequisite courses {', '.join(missing)}")
    else:
        messagebox.showerror("Error", "Student or course does not exist")


def process_scheduling_requests():
    if scheduling_queue.is_empty():
        messagebox.showinfo("Scheduling Requests", "No pending scheduling requests")
    else:
        req = scheduling_queue.dequeue()
        messagebox.showinfo("Processing Request", f"Processing request: {req}\nRemaining requests: {len(scheduling_queue.items)}")


def sort_students_by_course_grade():
    course_id = entry_course_grade.get()
    enrolled_students = [s for s in students if course_id in s.course_grades]
    if not enrolled_students:
        messagebox.showerror("Error", "No students are enrolled in this course")
        return
    sorted_students = merge_sort(enrolled_students.copy(), key=lambda s: s.course_grades[course_id])
    student_list = ""
    for s in sorted_students:
        student_list += f"- {s.fullName}: {s.course_grades[course_id]}\n"
    messagebox.showinfo(f"Students sorted by {course_id} grade", student_list)


# 6. Create GUI
root = tk.Tk()
root.title("Honkai-Peace Course Management System")
root.geometry("400x300")

# Create buttons
btn_view_courses = tk.Button(root, text="View all courses", command=view_all_courses)
btn_view_courses.pack(pady=5)

btn_sort_name = tk.Button(root, text="Sort students by name", command=sort_students_by_name)
btn_sort_name.pack(pady=5)

btn_sort_score = tk.Button(root, text="Sort students by average score", command=sort_students_by_average_score)
btn_sort_score.pack(pady=5)

# Create labels and entries for enrollment check
label_username = tk.Label(root, text="Student username:")
label_username.pack(pady=2)
entry_username = tk.Entry(root)
entry_username.pack(pady=2)

label_course_id = tk.Label(root, text="Course ID:")
label_course_id.pack(pady=2)
entry_course_id = tk.Entry(root)
entry_course_id.pack(pady=2)

btn_check_enrollment = tk.Button(root, text="Check enrollment eligibility", command=check_enrollment_eligibility)
btn_check_enrollment.pack(pady=5)

btn_process_requests = tk.Button(root, text="Process scheduling requests", command=process_scheduling_requests)
btn_process_requests.pack(pady=5)

# Create label and entry for course grade sorting
label_course_grade = tk.Label(root, text="Course ID:")
label_course_grade.pack(pady=2)
entry_course_grade = tk.Entry(root)
entry_course_grade.pack(pady=2)

btn_sort_course_grade = tk.Button(root, text="Sort students by course grade", command=sort_students_by_course_grade)
btn_sort_course_grade.pack(pady=5)

btn_exit = tk.Button(root, text="Exit", command=root.destroy)
btn_exit.pack(pady=20)

root.mainloop()
    